/**
 * 项目主体文件
 */
import React, { Component } from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
import debounce from 'lodash.debounce'
import qs from 'querystringify'

// layout
import AceEditor from './AceEditor.js'
import Header from './Header.js'
import ConsoleArea from './ConsoleArea.js'
import TurtleArea from './TurtleArea.js'
import ThemeAction from './ThemeAction.js'
import PublishModal from './PublishModal.js'
import ProjectModal from './ProjectModal.js'
import LoginModal from './LoginModal.js'
import ProjectNamePrompt from './ProjectNamePrompt.js'

import Draw from '../utils/draw.js'

// components
import Flex from '../components/Flex'
import Config from '../utils/config.js'
import Toast from '../components/Toast'
import Text from '../components/Text'
import Icon from '../components/Icon'
import Svg from '../components/Icon/svg'
import Color from '../components/Color'
import IconFullscreen from '../components/Icon/fullscreen.svg'
import IconFullscreenExit from '../components/Icon/fullscreen-exit.svg'
import IconBiaochi from '../components/Icon/biaochi.svg'

// actions
import * as actions from '../actionTypes/'
import './ace.css'

const Sk = window.Sk

class App extends Component {
    constructor(props) {
        super(props)

        this.state = {
            showRuler: false,
            isInputDone: false,
            inputValue: '',
            showInput: false,
            inputTips: '',
            valueForId: '',
        }

        this.drawer = null //非全屏坐标
        this.drawerFull = null //全屏坐标
        this.ace = null
        this.interval = null //定时器
        /**
         * 函数防抖
         * @type debounce与react结合时需这样定义}
         */
        this.doResize = debounce(this.doResize.bind(this), 500, {
            leading: false,
            trailing: true,
        })
    }

    componentWillMount() {
        this.initSkConfig()
        this.getCurrentUser()
        window.onresize = () => {
            this.doResize()
        }
    }

    componentDidMount() {
        this.getLocationSearch()
        this.handleDraw('drawer', 'xy', true)
    }

    //区分默认代码和通过id获取的代码的执行时机
    //valueForId: 通过id获取的code, 在saga里面只执行一次（getLocationSearch）
    componentWillReceiveProps(nextProps) {
        const { valueForId } = this.state
        const _valueForId = nextProps.editor.valueForId
        if (valueForId !== _valueForId && _valueForId) {
            this.setState(
                {
                    valueForId: _valueForId,
                },
                () => {
                    this.handleDelayRun()
                }
            )
        }
    }

    getLocationSearch() {
        const _search = window.location.search
        const search = qs.parse(_search)

        if (search && search.id) {
            this.props.dispatch({
                type: actions.FETCH_PROJECT_DETAIL,
                payload: search.id,
            })
        }
    }

    handleDelayRun() {
        setTimeout(() => this.handleRunCode('turtle-area'), 200)
    }

    encodeCharset(s) {
        try {
            s = decodeURIComponent(window.escape(s))
        } catch (e) {
            console.log(e)
        }
        return s
    }

    handleIput(val) {
        this.setState({
            showInput: true,
            inputValue: val,
            inputTips: val,
            isInputDone: false,
        })
        return new Promise((resolve, reject) => {
            this.interval = setInterval(() => {
                const { isInputDone, inputValue, inputTips } = this.state
                if (isInputDone) {
                    clearInterval(this.interval)
                    let _input = ''
                    if (inputValue) {
                        _input = inputValue.split(inputTips)[1]
                    }
                    resolve(_input.trim())
                }
            }, 100)
        })
    }

    handleInputEnd(e) {
        if (e.keyCode === 13) {
            this.props.dispatch({
                type: actions.HANDLE_PUT_CONSOLE,
                payload: e.target.value,
            })
            this.setState({
                isInputDone: true,
                inputValue: e.target.value,
                showInput: false,
            })
        }
    }

    handleInputChange(e) {
        this.setState({
            inputValue: e.target.value,
        })
    }

    initSkConfig() {
        !Sk.TurtleGraphics && (Sk.TurtleGraphics = {})
        Sk.configure({
            read: this.builtinRead,
            output: x => this.handleOutput(x),
            python3: true,

            inputfunTakesPrompt: true,
        })
    }

    doResize() {
        const { isTurtleFullscreen } = this.props.editor
        const { showRuler } = this.state
        if (!isTurtleFullscreen || !this.drawerFull || !showRuler) {
            return
        }
        const full = document.getElementById('xy-full')
        const { clientWidth, clientHeight } = document.body
        full.width = clientWidth
        full.height = clientHeight - Config.turtleTitleHeight

        this.handleRunCodeFullscreen('turtle-area-fullscreen')
    }

    getCurrentUser() {
        this.props.dispatch({
            type: actions.GET_CURRENT_USER,
        })
    }

    handleEditorChange(value) {
        this.props.dispatch({
            type: actions.HANDLE_EDITOR_CHANGE,
            payload: value,
        })
    }

    toggleEditorTheme() {
        const { theme } = this.props.editor
        this.props.dispatch({
            type: actions.TOGGLE_EDITOR_THEME,
            payload:
                theme === 'solarized_light' ? 'monokai' : 'solarized_light',
        })
    }

    builtinRead(x) {
        if (
            Sk.builtinFiles === undefined ||
            Sk.builtinFiles['files'][x] === undefined
        ) {
            throw new Error("File not found: '" + x + "'")
        }
        return Sk.builtinFiles['files'][x]
    }

    handleOutput(output) {
        const { showPublishModal } = this.props.project
        if (showPublishModal) {
            return
        }
        this.props.dispatch({
            type: actions.HANDLE_PUT_CONSOLE,
            payload: output,
        })
    }

    handleStopPlaying() {
        this.props.dispatch({
            type: actions.TOGGLE_PLAYING_TRURLE,
            payload: false,
        })
    }

    handleStopTurtle() {
        this.handleStopPlaying()
        Sk.TurtleGraphics.stop()
    }

    handleResetTurtle() {
        this.props.dispatch({
            type: 'HANDLE_CLEAR_CONSOLE',
        })
        if (Sk.TurtleGraphics.reset) {
            Sk.TurtleGraphics.reset()
        }
    }

    //非全屏的Turtle
    handleRunCode(id) {
        const { value, isPlaying } = this.props.editor

        if (!value) {
            return
        }

        if (isPlaying) {
            this.handleStopTurtle()
            return
        }

        this.props.dispatch({
            type: actions.TOGGLE_PLAYING_TRURLE,
            payload: true,
        })

        Sk.TurtleGraphics.width = 400
        Sk.TurtleGraphics.height = 400
        Sk.TurtleGraphics.target = id

        this.handleEval(value)
    }

    handleEval(value) {
        Sk.inputfun = v => this.handleIput(v)
        this.handleResetTurtle()
        Sk.misceval
            .asyncToPromise(function() {
                return Sk.importMainWithBody('<stdin>', false, value, true)
            })
            .then(() => {
                this.handleStopPlaying()
            })
            .catch(err => {
                this.handleStopPlaying()
                this.handleOutput(err.toString())
            })
    }

    //全屏时，只做画图逻辑
    handleRunCodeFullscreen(id) {
        const { value } = this.props.editor
        const { showRuler } = this.state
        if (!value) {
            return
        }
        const { clientWidth, clientHeight } = document.body
        Sk.TurtleGraphics.width = clientWidth
        Sk.TurtleGraphics.height = clientHeight - Config.turtleTitleHeight
        Sk.TurtleGraphics.target = id

        this.handleEval(value)

        if (!showRuler) {
            this.handleDraw('drawerFull', 'xy-full', true)
        } else {
            this.handleDraw('drawerFull', 'xy-full')
        }
    }

    handleDraw(type, id, isHide) {
        const _canvas = document.getElementById(id)
        const { clientWidth, clientHeight } = document.body
        // eslint-disable-next-line
        if (type == 'drawerFull') {
            _canvas.width = clientWidth
            _canvas.height = clientHeight - Config.turtleTitleHeight
        }
        setTimeout(() => (this[type] = new Draw(_canvas, isHide)))
    }

    handleClearConsole() {
        if (Sk.TurtleGraphics.reset) {
            Sk.TurtleGraphics.reset()
        }
        this.props.dispatch({
            type: actions.HANDLE_CLEAR_CONSOLE,
        })
        this.handleStopPlaying()
    }

    toggleSidebar() {
        const { showSidebar } = this.props.editor
        this.props.dispatch({
            type: actions.TOGGLE_DISPLAY_SIDEBAR,
            payload: !showSidebar,
        })
    }

    toggleTurtleFullscreen() {
        const { isTurtleFullscreen } = this.props.editor

        //全屏和非全屏都重新绘图
        if (!isTurtleFullscreen) {
            this.handleRunCodeFullscreen('turtle-area-fullscreen')
        } else {
            this.handleRunCode('turtle-area')
        }

        this.props.dispatch({
            type: actions.TOGGLE_TURTLE_FULLSCREEN,
            payload: !isTurtleFullscreen,
        })
    }

    toggleXY(type) {
        this.drawer && this.drawer.hideXY(type === 'none' ? true : false)
        this.drawerFull &&
            this.drawerFull.hideXY(type === 'none' ? true : false)
    }

    toggleRuler() {
        this.setState(prevState => {
            if (prevState.showRuler) {
                this.toggleXY('none')
            } else {
                this.toggleXY('block')
            }
            return {
                showRuler: !prevState.showRuler,
            }
        })
    }

    handleUndo() {
        const { editor } = this.ace.editor
        editor && editor.undo()
    }

    handleRedo() {
        const { editor } = this.ace.editor
        editor && editor.redo()
    }

    renderTurtleTitle() {
        const { isTurtleFullscreen } = this.props.editor
        const { showRuler } = this.state
        return (
            <TurleAreaTitle
                align="center"
                justify="space-between"
                isTurtleFullscreen={isTurtleFullscreen}
            >
                <Text color="white">海龟图</Text>
                <Flex justify="flex-end">
                    <Icon
                        onClick={this.toggleTurtleFullscreen.bind(this)}
                        size={24}
                        src={
                            isTurtleFullscreen
                                ? IconFullscreenExit
                                : IconFullscreen
                        }
                        pointer
                    />
                    &nbsp;&nbsp;&nbsp;&nbsp;
                    <Svg
                        onClick={this.toggleRuler.bind(this)}
                        size={24}
                        color={showRuler ? 'white' : Color.gray}
                        src={IconBiaochi}
                    />
                </Flex>
            </TurleAreaTitle>
        )
    }

    render() {
        const {
            value,
            theme,
            showSidebar,
            consoles,
            isTurtleFullscreen,
            isPlaying,
        } = this.props.editor
        const { showToast, toastContent } = this.props.common
        const {
            showProjectModal,
            showPublishModal,
            projectNameInput,
        } = this.props.project
        const { showInput, inputValue } = this.state
        return (
            <Root column>
                <Header />
                <Flex auto>
                    <Main auto>
                        <ThemeAction
                            toggleEditorTheme={this.toggleEditorTheme.bind(
                                this
                            )}
                            theme={theme}
                            toggleSidebar={this.toggleSidebar.bind(this)}
                            showSidebar={showSidebar}
                            handleUndo={this.handleUndo.bind(this)}
                            handleRedo={this.handleRedo.bind(this)}
                        />

                        <AceEditor
                            onChange={this.handleEditorChange.bind(this)}
                            value={value}
                            theme={theme}
                            ref={v => (this.ace = v)}
                        />
                    </Main>
                    <Sidebar show={showSidebar} column>
                        <ConsoleArea
                            handleClearConsole={this.handleClearConsole.bind(
                                this
                            )}
                            handleRunCode={this.handleRunCode.bind(
                                this,
                                'turtle-area'
                            )}
                            toggleSidebar={this.toggleSidebar.bind(this)}
                            consoles={consoles}
                            isPlaying={isPlaying}
                            handleInputEnd={this.handleInputEnd.bind(this)}
                            showInput={showInput}
                            inputValue={inputValue}
                            handleInputChange={this.handleInputChange.bind(
                                this
                            )}
                        />
                        {this.renderTurtleTitle()}
                        <TurtleArea
                            renderTurtleTitle={this.renderTurtleTitle.bind(
                                this
                            )}
                            showSidebar={showSidebar}
                            isTurtleFullscreen={isTurtleFullscreen}
                        />
                    </Sidebar>
                </Flex>
                {showPublishModal && <PublishModal />}
                {showProjectModal && <ProjectModal />}
                {projectNameInput.show && (
                    <ProjectNamePrompt
                        title={
                            projectNameInput.type === 'save'
                                ? '请输入作品名：'
                                : '另存为：'
                        }
                    />
                )}
                <LoginModal />
                {// 全局toast
                showToast && (
                    <Toast showToast={showToast}>{toastContent}</Toast>
                )}
            </Root>
        )
    }
}

let Home = connect(state => state)(App)

export default Home

const Root = styled(Flex)`
    background: #eee;
    height: 100%;
    overflow-x: hidden;
`

const TurleAreaTitle = styled(Flex)`
    height: 36px;
    flex: 0 0 36px;
    flex: ${({ isTurtleFullscreen }) =>
        isTurtleFullscreen ? '1 0 auto' : '0 0 auto'};
    padding-left: 20px;
    padding-right: 20px;
    background: ${Color.primary};
`

const Main = styled(Flex)`
    background: #eed;
    position: relative;
`

const Sidebar = styled(Flex)`
    width: ${({ show }) => (show ? `${Config.sidebarWidth}px` : '0')};

    transition: all 0.3s;
`



// WEBPACK FOOTER //
// ./src/containers/index.js